// Copyright 2023 Huawei Cloud Computing Technology Co., Ltd.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.


#ifndef _SOCKET_CLIENT_COMMON_H_
#define _SOCKET_CLIENT_COMMON_H_


#include <thread>
#include <mutex>
#include <string>
#include "client_common.h"

#define OK 0
#define ERROR -1

#define IS_RUNNING 1
#define IS_OVER 0

#define CONNECT_SUCCESS 0
#define CONNECT_FAILURE -1

#define DEFAULT_CONTEXT_ID 0xAA
#define DEFAULT_PORT 5039
#define DEFAULT_TIMES_OUT 10000

#define ENCODE_TYPE_E (0)
#define DECODE_TYPE_E (1)

#define REFERENCE_ADD_TYPE_E (0)
#define REFERENCE_CUT_TYPE_E (1)

#define RECV_FRAME_TIME_OUT 10000

#define RELEASE_SINGAL_COND 1

#define CLIENT_CONNECT_DELAY_TIME_US 200 * 1000
#define HEARTBEAT_TIME 30
#define MAX_TRY_CONNECT_INIT_NUM 20
#define DEFAULT_SELECT_TIME 1000000
#define HEART_BEAT_TIME 2000000

#define SOCKET_BUF_BLOCK 64
#define SOCKET_READ_BUF_MAX_LENGTH 1920 * 1080 * 2
#define SOCKET_WRITE_BUF_MAX_LENGTH 1920 * 1080 * 2

#define NUM_SCALE_SMALL_1000(a) (a / 1000)	
#define NUM_SCALE_BIG_1000(a) (a * 1000)

static const uint32_t SOCKET_HEAD_FLAG = 0x5A5A5A5A;
static const uint32_t PRE_D310_CAPABILITY_MAX = 1920 * 1080 * 100;//1080p * 100fps
static const uint32_t PRE_D310_CAP_MAX_COUNT = 6;



#define SOCKET_HEAD_FLAG_LENGTH 4
#define SOCKET_DATA_BUF_LENGTH 4
#define SOCKET_CMD_LENGTH 2

#define SOCKET_PROTOCOL_HEAD_LENGTH (SOCKET_HEAD_FLAG_LENGTH + SOCKET_CMD_LENGTH + SOCKET_DATA_BUF_LENGTH)


typedef enum
{
    KEEP_CONNECTED_CONDITIONAL,
    KEEP_CONNECTED_FOREVER,
    

}CONNECT_TYPE;

typedef enum{

    SOCKET_STATUS_IDLE = 0,                
    SOCKET_STATUS_INIT,                    
    SOCKET_STATUS_CONNECT,                 
    SOCKET_ERR                             

}CLIENT_STATUS_TYPE;


class SocketClient
{

private:
    int fdSock;

    std::string strIp;
    uint32_t port;

    int connectCnt;

public:    
    int readFlag;
        
public:
    SocketClient();
    virtual ~SocketClient();


private:

    void socketClientSetParamInfo(std::string ipAddr, uint16_t ipPort);

public:

    int socketClientGetfdInit(void);

    int socketClientConnectInit(int *status, int conType);

    int socketClientInit(std::string strIp, uint32_t port);

    int socketClientReadData(uint8_t *outBuf, uint32_t *outLen, void *pArgc);

    int socketClientWriteData(uint8_t *srcBuf, uint32_t srcLen, int status);

    void socketClientClose(void);

    const int socketClientfdParam() {return fdSock;}

};


class CommonClient
{

private:
    uint32_t pthreadTimeOut;

    std::shared_ptr<SocketClient> pSocketClient;

public:

    int clientStatus;
    int connectType;

public:
    std::shared_ptr<uint8_t> pWriteBuf;
    uint32_t writeBufLen;
    std::shared_ptr<uint8_t> pReadBuf;
    uint32_t readBufLen;

    uint32_t masterRefCnt;

    uint8_t contextId;

    uint8_t *pOutData; 
    uint32_t *pOutLen;
    uint16_t cmd;

protected:
    pthread_t pthreadId;

    int threadRunning;
	
public:
    CommonClient();
    virtual ~CommonClient();

private:

    int createThreadInit(void);

    static void *clientThreadInit(void *pArgc);

    int clientThreadFunc(void);

public:

    int dealConfig(const std::string configFilePath);

    int commonClientInit(std::string strIp, uint16_t port, uint32_t timeOut, int conType);

    int commonClientWrite(uint16_t cmdCtl, uint8_t *inBuf, uint32_t inLen);

    int commonClientRead(uint16_t cmdCtl, uint8_t *inBuf, int inLen, uint8_t *outBuf, int *outLen);

    int commonClientRecvDataAnalysis(void);

    int commonClientSendHeartbeatProtocol(void);

    int getFd(){ return pSocketClient->socketClientfdParam();}

    int getIP(const std::string &net_name, std::string &strIP);
};

#endif